import React from 'react';
import {message} from 'antd';
import {Icon} from '../index';
import MapTool, {BDStyle} from './MapTool';

import './index.scss';
/**
 * BMap是百度地图SDK：http://lbsyun.baidu.com/index.php?title=jspopular。
 * 使用BMap需要在index.html中添加百度地图SDK
 * BMapLib是百度地图开源库：https://lbsyun.baidu.com/index.php?title=open/library
 * BMapLib包含多个子库，需要在index.html中单独添加子库的SDK
 */
const {BMap, BMapLib} = window;
//加载百度地图SDK后，默认生成的常量。
const {BMAP_ANCHOR_BOTTOM_LEFT, BMAP_NAVIGATION_CONTROL_ZOOM} = window;

//鼠标绘制的模式
const drawMode = {
  //拖动地图。数据1表示类型，数据2表示工具类图标
  0: {type: 'finger', icon: 'map_finger'},
  //画点
  1: {type: 'marker', icon: 'map_marker'},
  //画线
  2: {type: 'polyline', icon: 'map_polyline'},
  //画圆
  3: {type: 'circle', icon: 'map_circle'},
  //画多边形
  4: {type: 'polygon', icon: 'map_polygon'},
  //画矩形
  5: {type: 'rectangle', icon: 'map_rectangle'}
};

/**
 * 百度地图：支持地图拖拽、驾车规划、鼠标绘制
 * 属性：
 * className：类名。
 * style：样式。类型：object。示例：{height: document.documentElement.clientHeight}。
 * ref：组件引用。类型：Function(MapBD)。示例：(MapBD) => this.MapBD = MapBD。
 * customBody：自定义界面。类型：ReactNode。
 * mapOptions：地图配置项。类型：object。示例：{center:'北京',zoom:14,onDragStart:()=>null,nDragEnd:()=>null}
 *    center：地图中点。类型：string|{lng: Number, lat: Number}
 *    zoom：缩放级别。类型：number。默认值：14。
 *    onDragStart：拖动开始事件。类型：Function()。
 *    onDragEnd：拖动结束事件。类型：Function()。
 */
export default class MapBD extends React.Component {
  static defaultProps = {
    className: '',
    mapOptions: {}
  };

  constructor(props) {
    super(props);
    this.state = {
      openDraw: false //是否开启鼠标绘制
    };
  }

  componentDidMount() {
    this.initMap();
  }

  render() {
    let {className, style} = this.props;
    return (
      <div className={`g-map ${className}`} style={style}>
        <div id="map"></div>
        {this.renderCustom()}
        {this.renderDraw()}
      </div>
    );
  }

  /**
   * 绘制自定义界面
   */
  renderCustom() {
    let {customBody} = this.props;
    return <div className="g-map-custom">{customBody}</div>;
  }

  /**
   * 绘制鼠标绘制工具栏
   * 需要在index.html引入DrawingManager_min.js。
   */
  renderDraw() {
    if (!this.draw) {
      return;
    }

    let {openDraw} = this.state;
    let {modes, overlay} = this.draw;
    let nowMode = this.drawingManager && this.drawingManager.getDrawingMode();
    let views = modes.map((item) => {
      //绘制模式
      let newItem = drawMode[item];
      let props = {
        key: item,
        className: nowMode === newItem.type ? 'g-map-draw-icon-high' : 'g-map-draw-icon',
        type: newItem.icon,
        onClick: () => {
          if (item === 0) {
            //设置绘制模式
            this.drawingManager.setDrawingMode(newItem.type);
            this.drawingManager.close();
          } else {
            if (overlay && overlay.getEditing && overlay.getEditing()) {
              message.error('请先退出编辑');
              return;
            }

            this.drawingManager.setDrawingMode(newItem.type);
            this.drawingManager.open();
          }
          this.setState({});
        }
      };
      return <Icon {...props} />;
    });
    return (
      <div className="g-map-draw" style={{display: openDraw ? '' : 'none'}}>
        {views}
      </div>
    );
  }

  /**
   * 初始化百度地图
   */
  initMap() {
    let {mapOptions} = this.props;
    let {center = '深圳', zoom = MapTool.defaultZoom} = mapOptions;
    //enableMapClick：是否启用景点点击，默认true。注意：map容器需要指定高度
    this.map = new BMap.Map('map', {enableMapClick: false});
    //个性化定制地图样式.在线定制:http://lbsyun.baidu.com/custom/
    this.map.setMapStyle({styleJson: BDStyle});
    //指定百度地图中心点与缩放比例
    this.map.centerAndZoom(MapTool.getPoint(center), zoom);
    //启用滚轮放大缩小
    this.map.enableScrollWheelZoom();
    //禁用双击放大
    this.map.disableDoubleClickZoom();

    this.initMapEvent();
    this.initMapControl();
  }

  /**
   * 初始化地图监听事件
   */
  initMapEvent() {
    let {mapOptions} = this.props;
    let {onDragStart, onDragEnd} = mapOptions;
    //监听拖动开始事件
    onDragStart && this.map.addEventListener('dragstart', onDragStart);
    onDragEnd && this.map.addEventListener('dragend', onDragEnd);
    //监听添加覆盖物事件
    this.map.addEventListener('addoverlay', ({type, target}) => {
      //如果开启了鼠标绘制
      if (this.drawingManager && this.drawingManager._isOpen) {
        //正在绘制的覆盖物
        this.draw.overlay = target;
      }
    });
  }

  /**
   * 初始化地图控件
   */
  initMapControl() {
    //缩放控件
    let control = new BMap.NavigationControl({anchor: BMAP_ANCHOR_BOTTOM_LEFT, type: BMAP_NAVIGATION_CONTROL_ZOOM});
    this.map.addControl(control);
  }

  /**
   * 初始化驾车规划
   */
  routeInit = () => {
    if (!this.drive) {
      //驾车配置
      this.drive = {
        route: null, //驾车规划
        markerStart: null, //起点标注
        markerEnd: null, //起点标注
        passingPoints: [], //驾车经过点
        passingLength: null, //驾车经过点的数量
        passingPolyLine: null //驾车经过点的折线图
      };
    }
  };

  /**
   * 驾车路线规划
   * @param config 配置
   * {
   *   start: {},//起点，格式：Point
   *   end: {},//终点，格式：Point
   *   iconType:2, //图标类型：1代表默认图标，2代表自定义图标，默认为2
   * }
   */
  routeDrive = (config = {}) => {
    this.routeInit();

    let {start, end, iconType = 1} = config;
    let {route, markerStart, markerEnd} = this.drive;
    if (route) {
      //第二次驾车规划时，禁止自动调整地图
      route.disableAutoViewport();
    } else if (iconType === 2) {
      //添加起点标注
      markerStart = this.drive.markerStart = MapTool.addPoint(this.map, start);
      markerEnd = this.drive.markerEnd = MapTool.addPoint(this.map, end);
    }

    let options = {
      renderOptions: {
        map: this.map,
        autoViewport: true //自动调整地图到合适的缩放
      },
      onSearchComplete: (results) => {
        if (route.getStatus() === 0) {
          if (iconType === 2) {
            //第二次驾车规划时，只修改标注的位置，不重新创建标注。注意：使用start变量时，数据不会变，所以使用config.start。
            markerStart.setPosition(config.start);
            markerEnd.setPosition(config.end);
          }

          let plan = results.getPlan(0);
          //驾车经过的点
          let points = plan.getRoute(0).Kq;
          //设置车辆方向
          this.routeDirection(markerStart, points);
        }
      },
      onMarkersSet: (pois) => {
        if (iconType === 2) {
          //清除默认起点图标
          this.map.removeOverlay(pois[0].marker);
          this.map.removeOverlay(pois[1].marker);
        }
      },
      onPolylinesSet: (routes) => {
        let polyline = routes[0].getPolyline(); //线覆盖物
        // polyline.setStrokeWeight(3);	// 设置Polyline的宽度。该方法有BUG。
        polyline.setStrokeColor('#1AC68C');
        polyline.draw(); // Polyline修改配置后，需要调用draw()重新绘制
      }
    };
    route = route || (this.drive.route = new BMap.DrivingRoute(this.map, options));
    //调用后，会自动清除上一次的数据（包括路线图）
    route.search(config.start, config.end);
  };

  /**
   * 设置驾车方向。注意：车辆起点与第一个途经点不一致。
   * @param marker 车牌标注,格式:Marker
   * @param points 途经点,格式:[{Point}]。Point为百度经纬度坐标。
   */
  routeDirection(marker, points = []) {
    if (!marker) {
      return;
    }
    //将经纬度转为平面坐标
    let startPixel = this.map.pointToPixel(marker.getPosition());
    let endPixel;
    points.some((item, index) => {
      //保证第二个点与第一个点的坐标不同
      return !startPixel.equals((endPixel = this.map.pointToPixel(item)));
    });
    //计算两点所在有向线段顺时针方向旋转的角度
    let deg = MapTool.angleCalculation(startPixel, endPixel);
    //设置顺时针方向旋转的角度
    marker.setRotation(deg);
    return deg;
  }

  /**
   * 清除驾车规划数据
   */
  routeClear = () => {
    this.drive.route.clearResults();
    this.drive.markerStart && this.map.removeOverlay(this.drive.markerStart);
    this.drive.markerEnd && this.map.removeOverlay(this.drive.markerEnd);
  };

  /**
   * 初始化鼠标绘制
   */
  drawInit() {
    if (!this.draw) {
      //鼠标绘制配置
      this.draw = {
        modes: [0, 4, 5], //开启的绘制模式，见drawMode
        overlay: null, //当前绘制的覆盖物
        overlayList: [], //所有绘制的覆盖物
        callback: null //绘制完成的回调事件，格式：(data,result)=>null
      };
    }
  }

  /**
   * 开启鼠标绘制：使用BMapLib.DrawingManager进行鼠标绘制
   * 需要在index.html引入DrawingManager_min.js。如果使用百度地图自带的工具栏，还需要引入DrawingManager_min.css。
   * 参考：http://api.map.baidu.com/library/DrawingManager/1.4/docs/symbols/BMapLib.DrawingManager.html
   * @param config 配置
   * {
   *   data:{},//传入的数据
   *   canEdit:false,//线面绘制完成后是否可编辑，默认false
   *   callback: (data,overlay)=>{}, //绘制完成的回调事件：data是传入的数据，overlay是绘制的多边形Polygon
   * }
   */
  drawOpen = (config = {}) => {
    this.drawInit();

    let {data, canEdit, callback} = config;
    if (!this.drawingManager) {
      let styleOptions = {
        fillColor: 'white', //填充颜色。当参数为空时，圆形将没有填充效果。
        fillOpacity: 0.5, //填充的透明度，取值范围0 - 1，默认为1。
        strokeColor: 'red', //边线颜色。
        strokeWeight: 3, //边线的宽度，以像素为单位。
        strokeOpacity: 1, //边线透明度，取值范围0 - 1，默认为1。
        strokeStyle: 'dashed' //边线的样式，solid或dashed。
      };
      let options = {
        isOpen: false, //是否开启绘制模式
        enableDrawingTool: false, //是否显示工具栏
        enableCalculate: false, //绘制是否进行测距(画线时候)、测面(画圆、多边形、矩形)
        polygonOptions: styleOptions, //多边形的样式
        rectangleOptions: styleOptions //矩形的样式
      };
      //实例化鼠标绘制工具
      this.drawingManager = new BMapLib.DrawingManager(this.map, options);
      //绘制完成的回调
      this.drawingManager.addEventListener('overlaycomplete', (e) => {
        let {overlay} = e;

        //拖动模式
        this.drawingManager.setDrawingMode(drawMode[0].type);
        //需要先关闭鼠标绘制，再开启线、面的编辑。因为map的addoverlay事件中，会根据绘制绘制状态，设置this.draw.overlay。
        this.drawingManager.close();

        this.draw.overlay = overlay;
        //开启线、面的编辑
        canEdit && overlay.enableEditing();
        callback(data, overlay);

        this.setState({});
      });
    }
    this.setState({openDraw: true});
  };

  /**
   * 移除正在鼠标绘制的多边形
   */
  drawRemoveOverlay = () => {
    let {overlay} = this.draw;
    if (overlay) {
      this.map.removeOverlay(overlay);
      this.draw.overlay = null;
    }
  };

  /**
   * 关闭鼠标绘制
   */
  drawClose = () => {
    if (this.drawingManager) {
      this.drawingManager.close();
    }
    this.setState({openDraw: false});
  };
}
